package main

import (
	"context"
	"log"
	"sync"
	"time"
)

func NoneBlockRead(ctx context.Context, chread chan interface{}, wt *sync.WaitGroup) {
	for {
		select {
		case <-ctx.Done():
			wt.Done()
			log.Println("receive main exit signal")
			return
		case data := <-chread:
			log.Println("receive ", data)
		default:
			select {
			case <-time.After(time.Second * 5):
				log.Println("time out")
			case data := <-chread:
				log.Println("receive ", data)
			case <-ctx.Done():
				log.Println("receive main exit signal")
				wt.Done()
				return
			}
		}
	}
}

func NoneBlockRead2(ctx context.Context, chread chan interface{}, wt *sync.WaitGroup) {
	defer func() {
		wt.Done()
	}()
	select {
	case <-ctx.Done():
		log.Println("receive main exit signal")
		return
	case data := <-chread:
		log.Println("receive data is ", data)
		return
	}
}

func main() {
	var wg = &sync.WaitGroup{}
	chread := make(chan interface{})
	wg.Add(1)
	ctx, _ := context.WithTimeout(context.TODO(), time.Second*10)
	go NoneBlockRead(ctx, chread, wg)

	select {
	case <-time.After(time.Second * 7):
		chread <- 1
	}

	wg.Add(1)
	ctx2, _ := context.WithTimeout(context.TODO(), time.Second*3)
	go NoneBlockRead2(ctx2, chread, wg)

	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			wg.Done()
		}()
	}

	waitch := make(chan int, 5)
	for i := 0; i < 5; i++ {
		go func() {
			waitch <- 1
		}()
	}

	for i := 0; i < 5; i++ {
		<-waitch
	}

	wg.Wait()
}
